home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Interactive Reference Guide / C-C++ Interactive Reference Guide.iso / c_ref / csource5 / 357_01 / cstar1.exe / DIR.C < prev    next >
C/C++ Source or Header  |  1991-06-18  |  18KB  |  939 lines

  1. /*
  2.     C* preprocessor -- directives
  3.  
  4.     source:  dir.c
  5.     started: October 7, 1985
  6.     version:
  7.         August 8, 1986
  8.         February 20, 1989:  added multiple path support to pp_include
  9.         March 8, 1989
  10.  
  11.     PUBLIC DOMAIN SOFTWARE
  12.  
  13.     The CSTAR program was placed in    the public domain on June 15, 1991,
  14.     by its author and sole owner,
  15.  
  16.         Edward K. Ream
  17.         1617 Monroe Street
  18.         Madison, WI 53711
  19.         (608) 257-0802
  20.  
  21.     CSTAR may be used for any commercial or non-commercial purpose.
  22.  
  23.     See cstar.h or cstar.c for a DISCLAIMER OF WARRANTIES.
  24. */
  25. #include "cstar.h"
  26.  
  27. /*
  28.     Externally visible routines.
  29. */
  30. void        do_pp(void);
  31.  
  32. /*
  33.     Internal routines.
  34. */
  35. static int    eval        (void);
  36. static int    prec        (int operator);
  37. static int    gt_prec        (int opr1, int opr2);
  38. static bool    isfnch        (int c, int delim);
  39. static int    pop_op        (void);
  40. static int    pop_val        (void);
  41. static void    psh_op        (int op);
  42. static void    push_val    (int val);
  43. static void    pp_else        (void);
  44. static void    pp_endif    (void);
  45. static void    pp_enum        (void);
  46. static void    pp_if        (void);
  47. static void    pp_ifdef    (bool flag);
  48. static void    pp_incl        (void);
  49. static void    pp_line        (void);
  50. static void    pp_undef    (void);
  51. static void    skip_lines    (void);
  52.  
  53. /*
  54.     The pp_def() routine, which handles #define directives, replaces the
  55.     i'th formal argument in the replacement string by the ARG_FLAG 
  56.     character followed by i + ARG_OFFSET.  The pp_expand() routine, which
  57.     handles macro calls, replaces these two characters by the i'th actual
  58.     argument.
  59.  
  60.     The ARG_FLAG character should be a character that can never appear in
  61.     normal text, but it MUST NOT BE NEGATIVE, so as to fit in a char.
  62. */
  63.  
  64. #define ARG_FLAG '$'
  65. #define ARG_OFFSET '0'
  66.  
  67.  
  68. /*
  69.     Do one preprocessor directive.
  70. */
  71.  
  72. #define EQL(string) str_eq(t_symbol+1,string+1)
  73.  
  74. void
  75. do_pp(void)
  76. {
  77.     char msg[100];
  78.  
  79.     TICK("do_pp");
  80.  
  81.     /* Get the directive into t_symbol[]. */
  82.     if (!isalpha(ch)) {
  83.         goto not_alpha;
  84.     }
  85.     t_id(t_symbol);
  86.  
  87.     /* Skip blanks after the directive. */
  88.     skip_bl();
  89.  
  90.     switch(t_symbol [0]) {
  91.  
  92.     case 'd':
  93.         if (t_length == 6 && EQL("define")) {
  94.             pp_def();
  95.             return;
  96.         }
  97.         goto not_pp;
  98.  
  99.     case 'e':
  100.         if (t_length == 4 && EQL("else")) {
  101.             pp_else();
  102.             return;
  103.         }
  104.         if (t_length == 4 && EQL("enum")) {
  105.             pp_enum();
  106.             return;
  107.         }
  108.         else if (t_length == 5 && EQL("endif")) {
  109.             pp_endif();
  110.             return;
  111.         }
  112.         goto not_pp;
  113.  
  114.     case 'i':
  115.         switch(t_length) {
  116.         case 2:    if (EQL("if")) {
  117.                 pp_if();
  118.                 return;
  119.             }
  120.             goto not_pp;
  121.         case 5:    if (EQL("ifdef")) {
  122.                 pp_ifdef(TRUE);
  123.                 return;
  124.             }
  125.             goto not_pp;
  126.         case 6:    if (EQL("ifndef")) {
  127.                 pp_ifdef(FALSE);
  128.                 return;
  129.             }
  130.             goto not_pp;
  131.         case 7:    if (EQL("include")) {
  132.                 pp_incl();
  133.                 return;
  134.             }
  135.             goto not_pp;
  136.         }
  137.         goto not_pp;
  138.  
  139.     case 'l':
  140.         if (t_length == 4 && EQL("line")) {
  141.             pp_line();
  142.             return;
  143.         }
  144.         goto not_pp;
  145.  
  146.     case 'p':
  147.         if (t_length == 6 && EQL("pragma")) {
  148.             /* Do NOTHING!! */
  149.             skip_pp();
  150.             return;
  151.         }
  152.         goto not_pp;
  153.     
  154.     case 'u':
  155.         if (t_length == 5 && EQL("undef")) {
  156.             pp_undef();
  157.             return;
  158.         }
  159.         goto not_pp;
  160.  
  161.     default:
  162.         goto not_pp;
  163.     }
  164.     
  165. not_alpha:
  166.     /*
  167.         Be more permissive than the new C standard.
  168.         Just skip the rest of the line.
  169.     */
  170.     skip_pp();
  171.     return;
  172.  
  173. not_pp:
  174.     strcpy(msg, t_symbol);
  175.     strcat(msg, " is not a valid preprocessor directive.");
  176.     t_error(msg);
  177.     skip_pp();
  178. }
  179.  
  180. #undef EQL
  181.  
  182.  
  183. /*
  184.     Define a list of constants.
  185.     #enum(constant, id1, id2, ... , idn)
  186. */
  187. static void
  188. pp_enum(void)
  189. {
  190.     register int flag;
  191.     register long val;
  192.     char symbol [100];
  193.     char txt [LONG_DIGITS];
  194.  
  195.     TICK("pp_enum");
  196.  
  197.     /* Get opening '(' */
  198.     skip_ws();
  199.     if (ch == '(') {
  200.         sysnext();
  201.     }
  202.     else {
  203.         goto bad_ch;
  204.     }
  205.  
  206.     /* Get initial constant. */
  207.     if (ch < '0' || ch > '9') {
  208.         goto bad_ch;
  209.     }
  210.     (void) t_number();
  211.     val = t_value;
  212.  
  213.     flag = FALSE;
  214.     for (;;) {
  215.  
  216.         skip_ws();
  217.         if (ch == ')' ) {
  218.             skip_pp();
  219.             return;
  220.         }
  221.         if (ch == ',') {
  222.             sysnext();
  223.             if (flag == TRUE) {
  224.                 val++;
  225.             }
  226.             flag = TRUE;
  227.             continue;
  228.         }
  229.  
  230.         if (ch == '\\') {
  231.             sysnext();
  232.             if (ch == '\r') {
  233.                 sysnext();
  234.             }
  235.             if (ch == '\n') {
  236.                 sysnext();
  237.                 do_nl();
  238.                 begin_line(FALSE);
  239.                 continue;
  240.             }
  241.             else {
  242.                 goto bad_ch;
  243.             }
  244.         }
  245.  
  246.         if (flag == FALSE || !isid1(ch)) {
  247.             goto bad_ch;
  248.         }
  249.  
  250.         /* Get the symbol into symbol[]. */
  251.         t_id(symbol);
  252.  
  253.         /* Look for '=' constant. */
  254.         skip_bl();
  255.         if (ch == '=') {
  256.             sysnext();
  257.             skip_ws();
  258.  
  259.             /* Get constant into val. */
  260.             if (ch < '0' || ch > '9') {
  261.                 goto bad_ch;
  262.             }
  263.             (void) t_number();
  264.             val = t_value;
  265.         }
  266.  
  267.         /* Enter the symbol with no arguments. */
  268.         convl2s(val, txt);
  269.         (void) mst_enter(symbol, txt, -1);
  270.  
  271.         /* Bump val and indicate a comma is expected. */
  272.         val++;
  273.         flag = FALSE;
  274.     }
  275.  
  276. bad_ch:    t_error("ill formed #enum");
  277.     skip_pp();
  278. }
  279.         
  280.     
  281. /*
  282.     Evaluate a constant expression to either true or false.
  283.     A constant expression consists of:
  284.  
  285.     1. integer constants or character constants
  286.     2. the unary - + and ~ operators
  287.     3. the binary + - * / & | ^ << >> == != < > <= >= oprators
  288.     4. the ternary ? : operator
  289.  
  290.     Identifiers are expanded if they are defined, otherwise they
  291.     are taken to have a value of zero.
  292.  
  293.     The code below evaluates constant expressions using an operator
  294.     precedence algorithm which employs an operator stack and an
  295.     operand stack.  The global t_evalstk[] array houses both stacks.
  296.     The operator stack starts at t_evalstk[0] and grows up.
  297.     The operand stack starts at t_evalstk[MAX_EVAL-1] and grows down.
  298.     The globals t_opptr and t_valptr are point at the top of each stack.
  299.     As usual, stack overflow happens when these two pointers "cross."
  300.     Several auxilliary routines are used to handle these stacks:
  301.     psh_op(), pop_op(), push_val() and pop_val();
  302. */
  303.  
  304. static int
  305. eval(void)
  306. {
  307.     register int op, op2, token, val1, val2, val3;
  308.  
  309.     TICK("eval");
  310.  
  311.     /* Initialize the operator and operand stacks. */
  312.     t_opptr = -1;
  313.     t_valptr = MAX_EVAL;
  314.  
  315.  
  316.     /* State S1: unary +, unary -, ~, constant or id is expected here. */
  317.  
  318. s1:
  319.     token = con_token();
  320.  
  321.     /* Push all unary ops. */
  322.     if (token == PLUS_TOK) {
  323.         psh_op(UPLUS_TOK);
  324.         goto s1;
  325.     }
  326.     else if (token == MINUS_TOK) {
  327.         psh_op(UMINUS_TOK);
  328.         goto s1;
  329.     }
  330.     else if (token == TILDE_TOK) {
  331.         psh_op(TILDE_TOK);
  332.         goto s1;
  333.     }
  334.  
  335.     /* We expect a constant or identifier here. */
  336.     if (token == INT_TOK || token == CHAR_TOK) {
  337.         push_val((int) t_value);
  338.     }
  339.     else if (token == ID_TOK) {
  340.         push_val(0);
  341.     }
  342.     else {
  343.         goto bad_expr;
  344.     }
  345.  
  346.     /* Perform all unary ops and enter state S2. */
  347.     while (t_opptr >= 0) {
  348.         switch (op = pop_op()) {
  349.         case UPLUS_TOK:                break;
  350.         case UMINUS_TOK: push_val(-pop_val());    break;
  351.         case TILDE_TOK:     push_val(~pop_val());    break;
  352.         default:     psh_op(op);        goto s2;
  353.         }
  354.     }
  355.  
  356.     /* State S2: binary op or end_of_expression expected here. */
  357.  
  358. s2:
  359.     token = con_token();
  360.  
  361.     /*
  362.         Perform binary operators until the operator stack is
  363.         empty or until token operator has a higher precedence
  364.         than the operator on the top of the operator stack.
  365.     */
  366.  
  367.     while (t_opptr >= 0 && gt_prec(t_evalstk[t_opptr], token)) {
  368.  
  369.         val2 = pop_val();
  370.         val1 = pop_val();
  371.         op   = pop_op();
  372.  
  373.         switch (op) {
  374.         case PLUS_TOK:        push_val(val1 + val2);    break;
  375.         case MINUS_TOK:        push_val(val1 - val2);    break;
  376.         case STAR_TOK:        push_val(val1 * val2);    break;
  377.         case DIV_TOK:        push_val(val2 ? (val1/val2) : 0);
  378.                     break;
  379.         case MOD_TOK:        push_val(val1 % val2);    break;
  380.         case AND_TOK:        push_val(val1 & val2);    break;
  381.         case OR_TOK:        push_val(val1 | val2);    break;
  382.         case XOR_TOK:        push_val(val1 ^ val2);    break;
  383.         case LSHIFT_TOK:    push_val(val1 << val2);    break;
  384.         case RSHIFT_TOK:    push_val(val1 >> val2);    break;
  385.         case EQUAL_TOK:        push_val(val1 == val2);    break;
  386.         case NE_TOK:        push_val(val1 != val2);    break;
  387.         case LT_TOK:        push_val(val1 <  val2);    break;
  388.         case GT_TOK:        push_val(val1 >  val2);    break;
  389.         case LE_TOK:        push_val(val1 <= val2);    break;
  390.         case GE_TOK:        push_val(val1 >= val2);    break;
  391.  
  392.         case COLON_TOK:        op2 = pop_op();
  393.                     if (op2 != QUESTION_TOK) {
  394.                         goto bad_expr;
  395.                     }
  396.                     val3 = pop_val();        
  397.                     push_val(val3 ? val1 : val2);
  398.                     break;
  399.         default:        goto bad_expr;
  400.         }
  401.     }
  402.         
  403.     /* Enter state S1 or return on end-of-expression. */
  404.     if (token == ZERO) {
  405.         skip_pp();
  406.         val1 = pop_val();
  407.         return val1;
  408.     }
  409.     else {
  410.         psh_op(token);
  411.         goto s1;
  412.     }
  413.  
  414. bad_expr:
  415.     t_error("bad constant expression--zero assumed");
  416.     skip_pp();
  417.     return 0;
  418. }
  419.  
  420.  
  421. /*
  422.     Return TRUE if opr1 has higher precedence than opr2.
  423.     If opr1 and opr2 have the same precedence, return TRUE
  424.     if they associate left to right.
  425.  
  426.     This code reflects the table on page 49 of K & R.
  427. */
  428.  
  429. static int
  430. gt_prec(register int opr1, register int opr2)
  431. {
  432.     register int prec1, prec2;
  433.  
  434.     TICK("gt_prec");
  435.  
  436.     prec1 = prec(opr1);
  437.     prec2 = prec(opr2);
  438.  
  439.     if (prec1 != prec2) {
  440.         /* Associativity doesn't matter. */
  441.         return prec1 > prec2;
  442.     }
  443.     else if (prec1 == 14 || prec1 == 3 || prec1 == 2) {
  444.         /* Associate right to left. */
  445.         return FALSE;
  446.     }
  447.     else {
  448.         /* Associate left to right. */
  449.         return TRUE;
  450.     }
  451. }
  452.  
  453.  
  454. /*
  455.     Return TRUE if c is legal in a file name.
  456.     Assume that the delim character is not legal.
  457. */
  458. static bool
  459. isfnch(int c, int delim)
  460. {
  461.     TICK("isfnch");
  462.  
  463.     switch (c) {
  464.     case '*':
  465.     case '?':
  466.     case '\n':
  467.     case '\r':
  468.     case ' ':
  469.     case '\t':
  470.     case END_FILE:
  471.                 return FALSE;
  472.  
  473.     default:        return c != delim;
  474.     }
  475. }
  476.  
  477.  
  478. /*
  479.     Return the precedence of an operator.
  480.  
  481.     This code reflects the table on page 49 of K & R.
  482. */
  483.  
  484. static int
  485. prec(int operator)
  486. {
  487.     TICK("prec");
  488.  
  489.     switch (operator) {
  490.     case TILDE_TOK:        return 14;
  491.     case STAR_TOK:
  492.     case DIV_TOK:
  493.     case MOD_TOK:        return 13;
  494.     case PLUS_TOK:
  495.     case MINUS_TOK:        return 12;
  496.     case LSHIFT_TOK:
  497.     case RSHIFT_TOK:    return 11;
  498.     case LT_TOK:
  499.     case LE_TOK:
  500.     case GT_TOK:
  501.     case GE_TOK:        return 10;
  502.     case EQUAL_TOK:
  503.     case NE_TOK:        return 9;
  504.     case XOR_TOK:        return 7;
  505.     case OR_TOK:        return 6;
  506.     case COLON_TOK:
  507.     case QUESTION_TOK:    return 3;
  508.     case ZERO:
  509.     case ERROR:        return ZERO;
  510.     default:        return ERROR;
  511.     }
  512. }
  513.  
  514.  
  515. /*
  516.     Routines to push and pop the operator and operand stacks.
  517. */
  518. static void
  519. psh_op(int op)
  520. {
  521.     TICK("psh_op");
  522.  
  523.     if (t_opptr + 1 < t_valptr) {
  524.         t_evalstk [++t_opptr] = op;
  525.         return;
  526.     }
  527.     fatal("psh_op: overflow\n");
  528. }
  529.  
  530. static int
  531. pop_op(void)
  532. {
  533.     TICK("pop_op");
  534.  
  535.     if (t_opptr >= 0) {
  536.         return t_evalstk [t_opptr--];
  537.     }
  538.     fatal("pop_op: underflow\n");
  539. }
  540.  
  541. static void
  542. push_val(int val)
  543. {
  544.     TICK("push_val");
  545.     TRACE("push_val", printf("push_val %d\n", val));
  546.  
  547.     if (t_valptr - 1 > t_opptr) {
  548.         t_evalstk [--t_valptr] = val;
  549.         return;
  550.     }
  551.     fatal("push_val: overflow\n");
  552. }
  553.  
  554. static int
  555. pop_val(void)
  556. {
  557.     TICK("pop_val");
  558.  
  559.     if (t_valptr < MAX_EVAL) {
  560.         TRACE("pop_val", printf("pop_val %d\n", t_evalstk[t_valptr]));
  561.         return t_evalstk [t_valptr++];
  562.     }
  563.     fatal("pop_val: underflow\n");
  564. }
  565.  
  566.  
  567. /*
  568.     Handle the #else directive.
  569. */
  570. static void
  571. pp_else(void)
  572. {
  573.     TICK("pp_else");
  574.  
  575.     if (t_iflevel == 0) {
  576.         t_error("#else ignored--no matching #if.");
  577.         skip_pp();
  578.     }
  579.     else if (t_ifstack [t_iflevel - 1] == TRUE) {
  580.         t_error("Duplicate #else ignored.");
  581.         skip_pp();
  582.     }
  583.     else {
  584.         t_ifstack [t_iflevel - 1] = TRUE;
  585.         skip_lines();
  586.     }
  587. }
  588.  
  589.  
  590. /*
  591.     Handle the #endif directive.
  592. */
  593. static void
  594. pp_endif(void)
  595. {
  596.     TICK("pp_endif");
  597.  
  598.     if (t_iflevel == 0) {
  599.         t_error("#endif ignored--no matching #if.");
  600.         skip_pp();
  601.     }
  602.     else {
  603.         t_iflevel--;
  604.         skip_pp();
  605.     }
  606. }
  607.             
  608.  
  609. /*
  610.     Handle the #if directive.
  611. */
  612. static void
  613. pp_if(void)
  614. {
  615.     TICK("pp_if");
  616.  
  617.     /* Indicate that no #else has been seen. */
  618.     if (t_iflevel >= MAX_IF) {
  619.         t_error("#if ignored--nested too deeply.");
  620.         skip_pp();
  621.         return;
  622.     }
  623.     t_ifstack [t_iflevel++] = FALSE;
  624.  
  625.     /* Skip lines if the constant expression evaluates to zero. */
  626.     if (eval() == 0) {
  627.         /* Skip until #else or #endif. */
  628.         skip_lines();
  629.     }
  630. }
  631.  
  632.  
  633. /*
  634.     Handle the #ifdef and #ifndef directives.
  635.  
  636.         flag == TRUE:    #ifdef
  637.         flag == FALSE:    #ifndef
  638. */
  639. static void
  640. pp_ifdef(int flag)
  641. {
  642.     register struct mst_node * p;
  643.     struct mst_node * mst_lookup();
  644.  
  645.     TICK("pp_ifdef");
  646.  
  647.     if(t_iflevel > MAX_IF) {
  648.         t_error("#ifdef or #ifndef ignored--nested too deeply.");
  649.         skip_pp();
  650.         return;
  651.     }
  652.  
  653.     if (!isid1(ch)) {
  654.         t_error("#ifdef or #ifndef ignored--identifier expected.");
  655.         skip_pp();
  656.         return;
  657.     }
  658.     
  659.     /* Get id into t_symbol[]. */
  660.     t_id(t_symbol);
  661.     skip_pp();
  662.     
  663.     /* Indicate that no #else has been seen. */
  664.     t_ifstack [t_iflevel++] = FALSE;
  665.  
  666.     /* Skip lines if required. */
  667.     p = mst_lookup(t_symbol);
  668.     if ((flag  && p == NULL) || (!flag && p != NULL)) {
  669.         /* Skip until #else or #endif. */
  670.         skip_lines();
  671.     }
  672. }
  673.  
  674.  
  675. /*
  676.     Handle the #include directive.
  677. */
  678. static void
  679. pp_incl(void)
  680. {
  681.     int err_flag;
  682.     char mess [100];
  683.     register int i, j;
  684.     unsigned char f_name [MAX_FILE_NAME];
  685.     unsigned char buffer [MAX_FILE_NAME];
  686.     unsigned char path_name [200];
  687.     unsigned char delim;
  688.  
  689.     TICK("pp_incl");
  690.  
  691.     /* File name is OK. */
  692.     err_flag = FALSE;
  693.  
  694.     /* Check for opening delimiter. */
  695.     if (ch == '"') {
  696.         delim = '"';
  697.         sysnext();
  698.     }
  699.     else if (ch == '<') {
  700.         delim = '>';
  701.         sysnext();
  702.     }
  703.     else {
  704.         err_flag = TRUE;
  705.         delim = '\r';
  706.     }
  707.  
  708.     /* Get file name into f_name[]. */
  709.     for (i = 0; i < MAX_FILE_NAME-1 && isfnch(ch, delim); i++) {
  710.         f_name[i] = ch;
  711.         sysnext();
  712.     }
  713.     f_name[i] = '\0';
  714.  
  715.     if (err_flag || ch != delim) {
  716.         strcpy(mess, "#include ");
  717.         strcat(mess, f_name);
  718.         strcat(mess, " ignored--bad delimiter.");
  719.         t_error(mess);
  720.         skip_pp();
  721.         return;
  722.     }
  723.  
  724.     /* Skip over the delimiter. */
  725.     sysnext();
  726.  
  727.     /*
  728.         Skip the line, including the newline character.
  729.         Do NOT call skip_past(), because we don't want to
  730.         write the old include-level mark here.  We also
  731.         don't want to write the NEW include-level mark here
  732.         because we don't know whether sysopen() will fail.
  733.  
  734.         We MUST, however, skip the line here, because after
  735.         sysopen() is called we would not be able to skip
  736.         characters in the old level.
  737.     */
  738.         
  739.     skip_pp();
  740.     if (ch == '\n') {
  741.         sysnext();
  742.     }
  743.     do_nl();
  744.  
  745.     if (t_inlevel >= MAX_INCLUDE) {
  746.         strcpy(mess, "#include ");
  747.         strcat(mess, f_name);
  748.         strcat(mess, " ignored--nested too deeply.");
  749.         t_line--;
  750.         t_error(mess);
  751.         t_line++;
  752.  
  753.         /* Add the include level mark. */
  754.         begin_line(TRUE);
  755.         return;
  756.     }
  757.  
  758.     /* Open the file. */
  759.     if(sysopen(f_name) == FALSE) {
  760.         for (i = 0; i < n_paths; i++) {
  761.             strcpy(path_name, paths [i]);
  762.             strcat(path_name, f_name);
  763.  
  764.             TRACEP("pp_incl", printf("attempting to open %s\n",
  765.                 path_name));
  766.  
  767.             if (sysopen(path_name) == TRUE) {
  768.                 return;
  769.             }
  770.         }
  771.         strcpy(mess, "#include ");
  772.         strcat(mess, f_name);
  773.         strcat(mess, " ignored--file not found.");
  774.         t_line--;
  775.         t_error(mess);
  776.         t_line++;
  777.     }
  778.  
  779.     begin_line(TRUE);
  780. }
  781.  
  782.  
  783. /*
  784.     Set the line number and file name.
  785. */
  786. static void
  787. pp_line(void)
  788. {
  789.     register int i;
  790.  
  791.     TICK("pp_line");
  792.  
  793.     (void) t_number();
  794.     t_line = CAST(int) t_value;
  795.  
  796.     /* See if an optional file name is present. */
  797.     skip_bl();
  798.     if (ch == '\n' || ch == '\r' || ch == END_FILE) {
  799.         return;
  800.     }
  801.  
  802.     /* Copy line to t_file[]. */
  803.     for(i = 0; i < MAX_FILE_NAME - 1; i++) {
  804.         if (ch == END_FILE || ch == '\n' || ch == '\r') {
  805.             break;
  806.         }
  807.         t_file[i] = CAST(char) ch;
  808.         sysnext();
  809.     }
  810.     t_file [i] = '\0';
  811.     skip_pp();
  812. }
  813.  
  814.  
  815. /*
  816.     Undefine a previously #defined variable.
  817. */
  818. static void
  819. pp_undef(void)
  820. {
  821.     TICK("pp_undef");
  822.  
  823.     /* Get the identifier into t_symbol[]. */
  824.     if (!isid1(ch)) {
  825.         t_error("#undef ignored--identifier expected.");
  826.         skip_pp();
  827.         return;
  828.     }
  829.     t_id(t_symbol);
  830.  
  831.     /* Delete the identifier. Give no warning if it doesn't exist. */
  832.     mst_delete(t_symbol);
  833.     skip_pp();
  834. }
  835.  
  836.  
  837. /*
  838.     Skip lines until a matching #else or #endif directive is found.
  839.     Thus,  interior #ifdef, #ifndef, #if and #else directives must
  840.     be recognized and dealt with.
  841.  
  842.     A fine point:  This code skips lines without doing any parsing of the
  843.     line.  The ONLY things this code looks for are lines which start with
  844.     #ifdef, #ifndef, #if or #else.  One should not detect "unknown"
  845.     preprocessor directives or other possible "errors," for the very good
  846.     reason that one wants to use conditional compilation to exclude lines
  847.     which might not even be written in the C language.
  848.  
  849.     Examples can be given where this action might be suspect.  Consider a
  850.     string which is continued from one line to the next using the backslash
  851.     newline convention.  If the continuation line starts with one of the
  852.     four directives that this routine is looking for then either the lex or
  853.     the person using the lex will become confused.  This is a minor hole in
  854.     the C language, and it seems better to ignore the fine points and do
  855.     what is sensible in most cases, namely skip entire lines as a unit.
  856.  
  857.     The routine skip_past() is used to do the skipping of exactly 1 line.
  858. */
  859.  
  860. #define EQL(string) str_eq(t_symbol,string)
  861. static void
  862. skip_lines(void)
  863. {
  864.     register int level;
  865.  
  866.     TICK("skip_lines");
  867.  
  868.     /* Just in case. */
  869.     if (t_iflevel <= 0) {
  870.         fatal("skip_lines:  can't happen.");
  871.     }
  872.  
  873.     /* No inner nexting yet. */
  874.     level = 0;
  875.  
  876.     /* Start a new line. */
  877. loop:
  878.     TICK("skip_lines1");
  879.  
  880.     if (ch == END_FILE) {
  881.         t_error("File ends inside range of #ifdef.");
  882.         return;
  883.     }
  884.  
  885.     if (ch == '\r') {
  886.         sysnext();
  887.         goto loop;
  888.     }
  889.  
  890.     /* Skip the line if it doesn't start with '#'. */
  891.     if (ch != '#') {
  892.         skip_past();
  893.         goto loop;
  894.     }
  895.  
  896.     /* Skip the line if '#' isn't followed by an id. */
  897.     sysnext();
  898.     if (!isid1(ch)) {
  899.         skip_past();
  900.         goto loop;
  901.     }
  902.  
  903.     /* Get the directive into t_symbol[]. */
  904.     t_id(t_symbol);
  905.  
  906.     if (EQL("ifdef") || EQL("ifndef") || EQL("if")) {
  907.         level++;
  908.     }
  909.     else if (EQL("else")) {
  910.         if (level > 0) {
  911.             ;
  912.         }
  913.         else if (t_ifstack [t_iflevel - 1] == FALSE) {
  914.             t_ifstack [t_iflevel - 1] = TRUE;
  915.             skip_pp();
  916.             return;
  917.         }
  918.         else {
  919.             t_error("Extra #else ignored.");
  920.         }
  921.     }
  922.     else if (EQL("endif")) {
  923.         if (level > 0) {
  924.             level--;
  925.         }
  926.         else {
  927.             t_iflevel--;
  928.             skip_pp();
  929.             return;
  930.         }
  931.     }
  932.     else {
  933.         skip_past();
  934.     }
  935.     goto loop;
  936. }
  937.  
  938. #undef EQL
  939.